﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Reflection;
using System.IO;
using System.Xml;
using System.Security.Cryptography;

namespace QF.Security
{
    public class Cryptographyer
    {
        private const string KEY_FILE = "qfoffice.key.config";
        
        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <returns>密文</returns>
        public string EncryptData(string plainText)
        {
            string encryptData = string.Empty;
            //创建一个新的 DES key.
            DESCryptoServiceProvider key = new DESCryptoServiceProvider();
            //设置数据加密标准 (DES) 算法的机密密钥和对称算法的初始化向量的值
            byte[] Key = null;
            byte[] IV = null;
            GetKEYAndIV(out Key, out IV);
            key.Key = Key;
            key.IV = IV;
            return EncryptData(plainText, key);
        }

        /// <summary>
        /// 通过 DESCryptoServiceProvider 解密字符串
        /// </summary>
        /// <param name="decryptedText">密文</param>
        /// <returns>明文</returns>
        public string DecryptData(string decryptedText)
        {
            string decryptData = string.Empty;
            //创建一个新的 DES key.
            DESCryptoServiceProvider key = new DESCryptoServiceProvider();
            //设置数据加密标准 (DES) 算法的机密密钥和对称算法的初始化向量的值
            byte[] Key = null;
            byte[] IV = null;
            GetKEYAndIV(out Key, out IV);
            key.Key = Key;
            key.IV = IV;
            return DecryptData(decryptedText, key);
        }

        /// <summary>
        /// 使用 MD5 加密字符串
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <returns>密文</returns>
        public string EncryptDataByHash(string plainText)
        {
            HashAlgorithm hashCryptoService = new SHA1Managed();
            byte[] bytIn = UTF8Encoding.UTF8.GetBytes(plainText);
            byte[] bytOut = hashCryptoService.ComputeHash(bytIn);
            return Convert.ToBase64String(bytOut);
        }
        
        /// <summary>
        /// 比较 MD5 加密字符串
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="hashedText">要比较的 hash 值</param>
        /// <returns>是否相同，是则返回 true, 否则返回 false</returns>
        public bool CompareHash(string plainText, string hashedText)
        {
            bool compare = false;
            string encryptData = EncryptDataByHash(plainText);
            compare = encryptData.Equals(hashedText);
            return compare;
        }
        
        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="key">对称算法的的抽象基类</param>
        /// <returns>密文</returns>
        private string EncryptData(string plainText, SymmetricAlgorithm key)
        {
            string encryptData = string.Empty;
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            using(MemoryStream ms = new MemoryStream())
            {
                CryptoStream cs = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
                cs.Write(plainTextBytes, 0, plainTextBytes.Length);
                cs.FlushFinalBlock();
                encryptData = Convert.ToBase64String(ms.ToArray());
            }
            Array.Clear(plainTextBytes, 0, plainTextBytes.Length);
            return encryptData;
        }       
        
        /// <summary>
        ///  解密字符串
        /// </summary>
        /// <param name="decryptedText">密文</param>
        /// <param name="key">对称算法的的抽象基类</param>
        /// <returns>明文</returns>
        private string DecryptData(string decryptedText, SymmetricAlgorithm key)
        {
            string decryptData = string.Empty;
            byte[] decryptedByteArray = Convert.FromBase64String(decryptedText);
            using(MemoryStream ms = new MemoryStream())
            {
                CryptoStream cs = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Write);
                cs.Write(decryptedByteArray, 0, decryptedByteArray.Length);
                cs.FlushFinalBlock();
                decryptData = Encoding.UTF8.GetString(ms.ToArray());
            }
            Array.Clear(decryptedByteArray, 0, decryptedByteArray.Length);
            return decryptData;
        }
        
        /// <summary>
        /// 获得数据加密标准 (DES) 算法的机密密钥和对称算法的初始化向量
        /// </summary>
        /// <param name="Key">数据加密标准 (DES) 算法的机密密钥</param>
        /// <param name="IV">对称算法的初始化向量</param>
        private void GetKEYAndIV(out  byte[] Key, out  byte[] IV)
        {
            Key = null;
            IV = null;
            using (Stream xmlInputStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + "." +  KEY_FILE))
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(xmlInputStream);
                XmlNodeList nodeList = xmlDoc.SelectSingleNode("Root").ChildNodes;
                foreach (XmlNode xn in nodeList)
                {
                    if (xn.NodeType != XmlNodeType.Element)
                    {
                        continue;
                    }
                    switch (xn.Name)
                    {
                        case "IV":
                            IV = Convert.FromBase64String(xn.InnerXml);
                            break;
                        case "KEY":
                            Key = Convert.FromBase64String(xn.InnerXml);
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }
}
